<script setup>
import { ref, nextTick } from "vue";
import { Command } from '@tauri-apps/api/shell';
import { open, message } from '@tauri-apps/api/dialog';
import { exists } from '@tauri-apps/api/fs';
import { path } from '@tauri-apps/api';

const baseFiles = ["MiniLoaderAll.bin", "parameter.txt"];
const scheme = [{
  name: 'uboot',
  imageName: 'uboot'
}, {
  name: 'resource',
  imageName: 'resource'
}, {
  name: 'boot_linux',
  imageName: 'boot_linux'
}, {
  name: 'ramdisk',
  imageName: 'ramdisk'
}, {
  name: 'system',
  imageName: 'system'
}, {
  name: 'vendor',
  imageName: 'vendor'
}, {
  name: 'sys-prod',
  imageName: 'sys_prod'
}, {
  name: 'chip-prod',
  imageName: 'chip_prod'
}, {
  name: 'updater',
  imageName: 'updater'
}, {
  name: 'chip_ckm',
  imageName: 'chip_ckm'
}, {
  name: 'userdata',
  imageName: 'userdata'
}];

const imageDir = ref("");
const imageList = ref([]);

let imageOK = false;
let locationID;
const deviceOK = ref(false);
const deviceId = ref("");
const isFlashing = ref(false);
const commandOutput = ref([]);
const commandWind = ref(null);

const asleep = timeout => new Promise(resolve => setTimeout(resolve, timeout));
const getDevice = async () => {
  try {
    const command = new Command("list-targets");
    command.stdout.on('data', line => {
      if (!line.includes('Empty')) {
        deviceId.value = line.substring(0, line.length - 2);
        deviceOK.value = true;
      }
    });
    await command.execute();
  } catch (error) {
    console.log(error);
  }
};
getDevice();

const imageFileCheck = async () => {
  imageList.value = new Array;
  let imageStatus = true;
  for (const file of baseFiles) {
    const fileFullName = imageDir.value + path.sep + file;
    const ret = await exists(fileFullName);
    console.log(fileFullName, ret);
    imageList.value.push({
      name: file.substring(0, 1),
      fileName: fileFullName,
      exist: ret
    });

    if (!ret) {
      imageStatus = false;
    }
  }
  for (const item of scheme) {
    const fileFullName = imageDir.value + path.sep + item.imageName + '.img';
    const ret = await exists(fileFullName);
    console.log(fileFullName, ret);
    imageList.value.push({
      name: item.name,
      fileName: fileFullName,
      exist: ret
    });

    if (!ret) {
      imageStatus = false;
    }
  }
  imageOK = imageStatus;
};

const chooseImageDir = async () => {
  const dirPath = await open({
    directory: true
  });
  imageDir.value = dirPath;
  if (dirPath) {
    await imageFileCheck();
  }
};

const addToCommandWind = content => {
  commandOutput.value.push(content);
  nextTick(() => {
    let scrollElem = commandWind.value;
    scrollElem.scrollTo({ top: scrollElem.scrollHeight, behavior: 'smooth' })
  });
}

const executeCmd = async (cmd) => {
  const command = new Command("execute-cmd", ['/c', cmd], {
    encoding: 'GB2312'
  });
  addToCommandWind('start to exec: ' + cmd);

  try {
    const result = await command.execute();
    if (result.stderr.length > 0) {
      addToCommandWind('exec failed: ' + result.stderr);
    }
  } catch (error) {
    console.log(cmd, error);
    addToCommandWind('exec failed: ' + JSON.stringify(error));
  }
}

const executeRkTool = async (cmd) => {
  const command = new Command("rk-tool", cmd);
  try {
    const result = await command.execute();
    return result;
  } catch (error) {
    console.log(cmd, error);
  }
}

const executeRkToolCmd = async (cmd) => {
  const basePath = await path.resourceDir();
  const toolPath = basePath.substring(4) + 'rk3568.exe';
  await executeCmd(`${toolPath} -s ${locationID} ${cmd}`);
  await asleep(200);
}

const rebootLoader = async () => {
  const cmd = `hdc -t ${deviceId.value} target boot -bootloader`
  await executeCmd(cmd);
  await asleep(5000);
};

const getLocationId = async () => {
  const result = await executeRkTool('LD');
  if (result) {
    const tagName = 'LocationID=';
    const pos = result.stdout.indexOf(tagName);
    const endPos = result.stdout.indexOf('\t', pos);
    if (pos > 0 && pos < result.stdout.length) {
      locationID = result.stdout.substring(pos + tagName.length, endPos);
      console.log('locationID', locationID);
    } else {
      throw 'get locationID failed'
    }
  }
  await asleep(2000);
}

const resumeFormBootLoader = async () => {
  await executeRkToolCmd('RD');
  await asleep(15000);
}

const flashBin = async () => {
  await executeRkToolCmd(`UL ${imageList.value[0].fileName} -noreset`);
  await asleep(3000)
}

const flashParameter = async () => {
  await executeRkToolCmd(`DI -p ${imageList.value[1].fileName}`);
  await asleep(3000)
}

const flashImage = async (imageItem) => {
  await executeRkToolCmd(`DI -${imageItem.name} ${imageItem.fileName}`);
}

const flashDevice = async () => {
  if (!deviceOK.value) {
    await message('请先连接设备', { title: '提示', type: 'error' });
    return;
  }

  if (!imageOK) {
    await message('请选择正确的镜像目录', { title: '提示', type: 'error' });
    return;
  }

  isFlashing.value = true;
  await rebootLoader();
  await getLocationId();
  await flashBin();
  await flashParameter();

  const baseLen = baseFiles.length;
  for (let i = 0; i < scheme.length; i++) {
    await flashImage(imageList.value[i + baseLen]);
  }

  await resumeFormBootLoader();
  isFlashing.value = false;
};

const unCompressFile = async () => {
  const postfix = 'tar.gz';
  const gzFileName = await open({
    filters: [{
      name: postfix,
      extensions: [postfix]
    }]
  });
  if (gzFileName) {
    const dstDir = gzFileName.substring(0, gzFileName.length - postfix.length - 1);
    await executeCmd('mkdir ' + dstDir);
    await executeCmd('tar -xzvf ' + gzFileName + ' -C ' + dstDir);
    await message('执行成功', { title: '提示', type: 'info' });
  }
}
</script>

<template>
  <div class="control-area">
    <button @click="getDevice">获取设备</button>
    <button @click="chooseImageDir">选择镜像路径</button>
    <button @click="flashDevice">开始烧录</button>
    <button @click="unCompressFile">解压tar.gz</button>
    <h2 v-if="isFlashing" style="color: red;margin-left: 100px;">正在烧录，请不要操作设备</h2>
  </div>
  <div class="normal-flex">
    <div style="display: inline-block; width: 500px;">设备：{{ deviceId }}</div>
    <div style="display: inline-block;">镜像路径：{{ imageDir }}</div>
  </div>
  <table style="margin-top: 10px;">
    <thead>
      <tr>
        <th style="width: 100px;">区域</th>
        <th style="width: 700px;">镜像路径</th>
        <th>状态</th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="imageItem in imageList">
        <td>{{ imageItem.name }}</td>
        <td>{{ imageItem.fileName }}</td>
        <td>{{ imageItem.exist ? 'ok' : 'error' }}</td>
      </tr>
    </tbody>
  </table>
  <div class="command-output" ref="commandWind">
    <p v-for="line in commandOutput">{{ line }}</p>
  </div>
</template>

<style scoped>
.control-area {
  display: flex;
  align-items: center;
  height: 80px;
}

.normal-flex {
  display: flex;
  align-items: center;
  padding: 10px 0px;
}

.normal-flex button {
  margin-right: 10px;
}

.image-name {
  display: inline-block;
  width: 800px;
  padding: 4px 0px;
}

table {
    border-collapse:collapse;
}
table,th, td {
    border: 2px solid lightblue;
}
.command-output {
  background-color: beige;
  max-height: 200px;
  overflow: auto;
  scroll-behavior: auto;
}
</style>
